﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;

namespace GENERIC.DBProvider
{
    /// <summary>
    /// Classe de base pour les Provider
    /// </summary>
    public abstract class DBProvider : IDisposable
    {
        #region Attributs

        private DbConnection m_connection;

        #endregion

        #region Constructor

        /// <summary>
        /// Initialise une nouvelle instance de la classe ProviderBase
        /// </summary>
        /// <param name="connectionString">chaîne de donnexion</param>
        /// <param name="decryptPassword">true pour décrypter le mot de passe, false sinon</param>
        public DBProvider(string connectionString)
        {
            ConnectionString = GetConnectionString(connectionString);
        }

        #endregion

        #region Proprerties

        /// <summary>
        /// Obtient la chaîne de connexion
        /// </summary>
        public string ConnectionString
        {
            get;
            private set;
        }

        /// <summary>
        /// Obtient le type de connexion
        /// </summary>
        public abstract eConnectionType ConnectionType { get; }

        /// <summary>
        /// Obtient la clé pour la source de données dans la chaîne de connexion
        /// </summary>
        protected virtual string ConnectionStringDataSourceKey
        {
            get { return "Data Source"; }
        }

        /// <summary>
        /// Obtient la clé pour l'utilisateur dans la chaîne de connexion
        /// </summary>
        protected virtual string ConnectionStringUserIDKey
        {
            get { return "User ID"; }
        }

        /// <summary>
        /// Obtient la clé pour le mot de passe dans la chaîne de connexion
        /// </summary>
        protected virtual string ConnectionStringPasswordKey
        {
            get { return "Password"; }
        }

        /// <summary>
        /// Obtient le nom de la base de données
        /// </summary>
        public virtual string DatabaseName
        {
            get { return DataSource; }
        }

        /// <summary>
        /// Obtient le nom de la source de données
        /// </summary>
        public virtual string DataSource
        {
            get
            {
                return CreateDbConnectionStringBuilder(ConnectionString) [ConnectionStringDataSourceKey].ToString();
            }
        }

        /// <summary>
        /// Obtient l'utilisateur
        /// </summary>
        public string UserId
        {
            get
            {
                return CreateDbConnectionStringBuilder(ConnectionString)[ConnectionStringUserIDKey].ToString();
            }
        }

        /// <summary>
        /// Obtient le mot de passe
        /// </summary>
        public string Password
        {
            get
            {
                return CreateDbConnectionStringBuilder(ConnectionString)[ConnectionStringPasswordKey].ToString();
            }
        }

        /// <summary>
        /// Obtient le nom du serveur
        /// </summary>
        public virtual string ServerName
        {
            get { return "Nom du serveur: " + DataSource; }
        }

        /// <summary>
        /// Obtient la connexion
        /// </summary>
        protected DbConnection Connection
        {
            get
            {
                if (m_connection == null)
                {
                    m_connection = CreateDbConnection();
                    if (m_connection != null)
                    {
                        m_connection.ConnectionString = ConnectionString;
                    }
                }
                return m_connection;
            }
            set { m_connection = value; }
        }

        #endregion

        #region Méthodes

        /// <summary>
        /// Obtient la valeur d'une propriété
        /// </summary>
        /// <param name="propertyName">nom de la propriété</param>
        /// <returns>valeur de la propriété</returns>
        public object GetPropertyValue(string propertyName)
        {
            return GetType().GetProperty(propertyName).GetValue(this, null);
        }

        /// <summary>
        /// Création du constructeur de chaîne de connexion
        /// </summary>
        /// <param name="connectionString">chaîne de connexion</param>
        /// <param name="password">mot de passe</param>
        /// <returns>un nouveau constructeur de chaîne de connexion</returns>
        protected abstract DbConnectionStringBuilder CreateDbConnectionStringBuilder(string connectionString);

        /// <summary>
        /// Obtient la chaîne de connexion
        /// </summary>
        /// <param name="connectionString">la chaîne de connexion</param>
        /// <returns></returns>
        protected string GetConnectionString(string connectionString)
        {
            return CreateDbConnectionStringBuilder(connectionString).ConnectionString;
        }

        /// <summary>
        /// Ouvre une connexion à la base de données
        /// </summary>
        /// <returns>la connexion</returns>
        public DbConnection OpenConnection()
        {
            DbConnection connection = Connection;
            if (connection != null)
            {
                var connectionState = connection.State;
                if (connectionState == ConnectionState.Broken)
                {
                    connection.Dispose();
                    Connection = null;
                }
                else
                {
                    if (connectionState == ConnectionState.Closed)
                    {
                        connection.Open();
                    }
                }
            }
            return m_connection;
        }

        /// <summary>
        /// Fermeture de la connexion
        /// </summary>
        public void CloseConnection()
        {
            var connection = Connection;
            if (connection != null && connection.State == ConnectionState.Open)
            {
                connection.Close();
            }
        }

        /// <summary>
        /// Création de la connexion à la base de données
        /// </summary>
        /// <returns>la nouvelle connexion</returns>
        protected abstract DbConnection CreateDbConnection();

        /// <summary>
        /// Test la connexion
        /// </summary>
        /// <returns>true si la connexion est réussie, false sinon</returns>
        public bool TryConnection()
        {
            OpenConnection();
            CloseConnection();
            return true;
        }

        /// <summary>
        /// Clône l'objet courant
        /// </summary>
        /// <returns>un clône de l'objet courant</returns>
        public DBProvider Clone()
        {
            return (DBProvider)Activator.CreateInstance(GetType(), ConnectionString);
        }

        #endregion

        #region IDisposable Membres

        /// <summary>
        /// Libère toutes les ressources
        /// </summary>
        public void Dispose()
        {
            DbConnection connection = m_connection;
            if (connection != null)
            {
                try
                {
                    connection.Dispose();
                }
                finally
                {
                    Connection = null;
                }
            }
        }

        #endregion
    }
}
